import json
import os

import pandas as pd

from noflip_web.globals import engine_ins_dc
from datetime import timedelta
import statistics
from conf.constant import IntervalMap, VariableDc
from django.http import JsonResponse
from conf.conf import conf_json_path, var_json_path
import copy
import random
import string


def update_active_model(engine_ins):
    """更新激活的模型，并将引擎设为当前活跃"""
    model_name = engine_ins.variable_key
    # 设置active_engine为model_name，并设置all_variable中相应模型字典的selected为true，其余字典的selected为false
    engine_ins_dc["active_engine"] = model_name
    for k, v in engine_ins_dc["all_variable"].items():
        if k == model_name:
            v["selected"] = True
        else:
            v["selected"] = False
    # 将新建的engine加入variable的single_engine_dc中，键为model_name
    engine_ins_dc["single_engine_dc"][model_name] = engine_ins
    # 保存变量数据到本地
    save_var_json()


def send_data_to_front(data):
    return JsonResponse(data)


def save_global_send_data(data):
    if "model_data" in data:
        if data["model_data"]["selected"]:
            # 保存全局数据
            save_var_json()
        else:
            # 保存全局数据
            save_var_json()
            # raise ValueError("当前model未选中，逻辑错误")
    else:
        pass

    # 发送至前端
    return send_data_to_front(data)


def data_df_interval(data_df: pd.DataFrame):
    # 读取数据文件的前20组
    temp_df = data_df.head(20)
    temp_index_ls = temp_df.index.tolist()
    temp_timedelta_ls = []
    for i in range(len(temp_index_ls) - 1):
        temp_timedelta_ls.append(temp_index_ls[i + 1] - temp_index_ls[i])
    mode_value: timedelta = statistics.mode(temp_timedelta_ls)
    # 根据timedelta通过IntervalMap反向获取相应的Interval实例
    interval_ins = None
    interval_val = None
    for k, v in IntervalMap.items():
        if v == mode_value:
            interval_ins = v
            interval_val = k
            break
    if interval_ins is None:
        raise ValueError("获取数据文件的Interval实例失败。")

    return interval_val


def judge_title(new_title, all_variable, old_title=None):
    """判断新增的模型名是否与现有其他模型内容重复，要求既不与初始key一致，也不与value中的lab_var_part2_1的title一致"""
    # 找出title对应的model_name_code
    model_name_code = None
    if old_title is not None:
        for k, v in all_variable.items():
            if v["lab_var_part2_1"]["title"] == old_title:
                model_name_code = k
        if model_name_code is None:
            raise ValueError("根据旧名称未找到对应的模型，逻辑错误")
    for k, v in all_variable.items():
        if k == model_name_code:
            continue
        if new_title == k:
            return False
        elif new_title == v["lab_var_part2_1"]["title"]:
            return False
        else:
            pass

    return True


def gen_new_variable(title, sub_title, all_variable: dict):
    """生成一个新的variable，值为默认，并自动生成一个model_name_code"""
    # 判断是否可用
    if judge_title(title, all_variable):
        pass
    else:
        raise ValueError("当前模型名称不可用", title, all_variable)
    variable_dc = copy.deepcopy(VariableDc)
    variable_dc["lab_var_part2_1"]["title"] = title
    variable_dc["lab_var_part2_1"]["sub_title"] = sub_title

    model_name_code = generate_random_string()

    return model_name_code, variable_dc


def generate_random_string(length=5):
    # 定义字符集，包括大写字母、小写字母和数字
    characters = string.ascii_letters + string.digits
    # 使用random.choice()从字符集中随机选择指定长度的字符
    random_string = ''.join(random.choice(characters) for _ in range(length))
    return random_string


def get_sample(arr_ls, num, type="lr"):
    if type == "":
        raise ValueError("暂未开发")
    elif type == "lr":
        step_num = num - 1
        step_len = len(arr_ls) // step_num
        new_arr_ls = []
        for i in range(step_num):
            new_arr_ls.append(arr_ls[i * step_len])
        new_arr_ls.append(arr_ls[-1])
        return new_arr_ls


def set_active_model(all_variable):
    """根据variable的选中项来设置全局变量中的active_engine"""
    # 刚选中时所有model的所有part均为未执行状态
    selected_num = 0
    for k, v in all_variable.items():
        if v["selected"]:
            engine_ins_dc["active_engine"] = k
            selected_num += 1
        engine_ins_dc["all_variable"][k]["lab_var_part2_2"]["execute"] = False
        engine_ins_dc["all_variable"][k]["lab_var_part2_3"]["execute"] = False
        engine_ins_dc["all_variable"][k]["lab_var_part2_4"]["execute"] = False
        engine_ins_dc["all_variable"][k]["lab_var_part2_5"]["execute"] = False
    if selected_num == 0:
        engine_ins_dc["active_engine"] = ""
    elif selected_num == 1:
        pass
    else:
        raise ValueError("选中的模型数量大于1，逻辑错误。")
    return engine_ins_dc["active_engine"]


def load_var_json():
    """将本地json加载到全局变量engine_ins_dc"""
    # 从 JSON 文件读取数据
    with open(var_json_path, 'r', encoding='utf-8') as json_file:
        data = json.load(json_file)
    # 如果json中的数据为空，生成var
    if not data:
        title = "默认model"
        sub_title = "无模型时默认生成，请修改模型信息。"
        model_name_code, variable_dc = gen_new_variable(title, sub_title, engine_ins_dc["all_variable"])
        data = {model_name_code: variable_dc}
    # 将variable放在全局变量
    engine_ins_dc["all_variable"] = data
    # 根据variable的选中项来设置全局变量中的active_engine
    model_name_code = set_active_model(data)
    return model_name_code


def save_var_json():
    """将全局变量engine_ins_dc中all_variable的保存到本地"""
    data = engine_ins_dc["all_variable"]
    # 替换保存
    with open(var_json_path, 'w') as json_file:
        json.dump(data, json_file, indent=4)
    pass


def load_conf_json():
    # 从 JSON 文件读取数据
    with open(conf_json_path, 'r') as json_file:
        data = json.load(json_file)
    return data


def save_conf_json(data_dc):
    with open(conf_json_path, 'w') as json_file:
        json.dump(data_dc, json_file, indent=4)
    pass


def safe_to_csv(data, path):
    # 获取文件夹路径（不包括文件名）
    folder_path = os.path.dirname(path)

    # 如果文件夹不存在，创建它
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)

    data.to_csv(path, index=True)
